# This file is part of ModularBot.
# Copyright (C) 2005 Pierre Ducroquet (pierre.linux59@wanadoo.fr)

# ModularBot is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.

# ModularBot is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with ModularBot; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

import threading, time

class Context:
	"""A context is an object, associated to each bot call.
	It contains the user, the channel and the message, which were previously sent through separated arguments,
	but also a say command, the "grep" filter, it's able to say whether it's threaded or not..."""
	def __init__ (self, user, channel, bot, text):
		# Initialise Context with current informations
		self.user_full = user
		self.user = user.split('!', 1)[0]
		self.channel = channel
		self.bot = bot
		
		# This is to remove the need of BotName: in commands inside queries or notice...
		# This message value is temporary, and is to be handled directly only by global calls... 
		# The Core will modify it after the run of every global call.
		if channel == bot.nickname:
			self.message = "%s: %s" % (bot.nickname, text)
			self.channel = self.user
		else:
			self.message = text
		
		# Set default values to other Context parts...
		self.stop = False # stop is to ask the core not to execute the command. It's to be set by globalcalls for instance
		self.grep = ""
		self.timing = False
		self.noticing = False
		self.is_admin = False
		self.from_notice = False
	
	def raw_exec (self):
		if self.timing:
			starttime = time.time()
		if self.cmd_func.func_code.co_argcount == 3:
			# A function with 3 args : self, context, command_args
			ret = self.cmd_func(self, self.command_args)
		else:
			ret = self.cmd_func(self)
		if hasattr(self.cmd_func, "returns") and ret != None:
			# returns => "string", "list", "dic"
			if self.cmd_func.returns == "string":
				self.say(ret)
			elif self.cmd_func.returns == "list":
				self.say(" ; ".join(ret))
			elif self.cmd_func.returns == "dic":
				for item in ret.items():
					self.say("%s => %s" % (item[0], item[1]))
		self.grep = ""
		if self.timing:
			diff = time.time() - starttime
			if diff < 1:
				self.say ("%s millisecondes..." % str(diff*1000) )
			else:
				self.say ("%s secondes..." % str(diff) )
		
	def launch (self):
		if hasattr(self.cmd_func, "conflict_with"):
			try:
				print self.bot.threads
				assert not(self.bot.threads[self.cmd_func.conflict_with]._Thread__stopped)
				self.say ("Conflicting with thread %s" % self.cmd_func.conflict_with)
				return
			except:
				print "An exception occured here."
				pass
		if hasattr(self.cmd_func, "threaded"):
			print self.bot.threads
			try:
				assert not(self.bot.threads[self.cmd_func.func_name]._Thread__stopped)
				self.say ("Thread already launched")
			except:
				thread = threading.Thread(target=self.raw_exec)
				self.bot.threads[self.cmd_func.func_name] = thread
				thread.start()
		else:
			self.raw_exec()
	
	# This is hackish...
	# The args are reverted if you forget one arg
	def say (self, user, message = ""):
		if message == "":
			message = user
			user = ""
		if type(message) == list:
			messages = []
			for msg in message:
				if self.grep in msg:
					messages.append(msg)
			for msg in messages[:7]:
				self.say(user, msg)
			if len(messages) > 7:
				self.say(user, "Too many messages, %i left" % (len(messages)-7))
		if not self.grep in message:
			return
		if self.noticing:
			self.bot.notice(self.user, message)
		elif user == "":
			self.bot.say(self.channel, message)
		else:
			self.bot.say(user, message)
	
	def notice (self, user, message = ""):
		if message == "":
			message = user
			user = ""
		if type(message) == list:
			messages = []
			for msg in message:
				if self.grep in msg:
					messages.append(msg)
			for msg in messages[:7]:
				self.say(user, msg)
			if len(messages) > 7:
				self.say(user, "Too many messages, %i left" % (len(messages)-7))
		if not self.grep in message:
			return
		if user == "":
			self.bot.notice(self.user, message)
		else:
			self.bot.notice(user, message)
	
	def error (self, message):
		if self.noticing:
			self.bot.notice(self.user, message)
		else:
			self.bot.say(self.channel, message)
